#include "grate_test_utils.h"
#include "grate/dfa.h"
#include "grate/scc_builder.h"
#include "grate/util/common.h"

using growth_rate::testing::TableDFA;
using growth_rate::DFAInterface;
using growth_rate::SccPartition;
using growth_rate::ScopedArray;

namespace {

TEST(DFAInterfaceTest, HasLoop) {
  int trans_table[] = {1, 1, 1,
                       1, -1, 2,
                       3, 3, 3,
                       -1, -1, 3};
  TableDFA dfa(4, 3, trans_table);
  EXPECT_FALSE(dfa.has_loop(0));
  EXPECT_TRUE(dfa.has_loop(1));
  EXPECT_FALSE(dfa.has_loop(2));
  EXPECT_TRUE(dfa.has_loop(3));
}

static void test_valid_edges(const DFAInterface &dfa,
    const int *exp_from, const int *exp_to, size_t exp_size) {
  EXPECT_EQ(exp_size, dfa.number_of_valid_edges());
  ScopedArray<DFAInterface::Edge> edges(exp_size);
  dfa.dump_valid_edges(edges.data());
  for (size_t i = 0; i < exp_size; i++) {
    EXPECT_EQ(exp_from[i], edges[i].from);
    EXPECT_EQ(exp_to[i], edges[i].to);
  }
}

TEST(DFAInterfaceTest, ValidEdges) {
  {
    int trans_table[] = {1, -2, 1,
                         1, -1, 2,
                         3, 3, 3,
                         -1, -1, 3};
    TableDFA dfa(4, 3, trans_table);
    int exp_from[] = {0, 0, 1, 1, 2, 2, 2, 3};
    int exp_to[]   = {1, 1, 1, 2, 3, 3, 3, 3};
    ASSERT_EQ(ARRAYSIZE(exp_from), ARRAYSIZE(exp_to));
    test_valid_edges(dfa, exp_from, exp_to, ARRAYSIZE(exp_from));
  }
  {
    int trans_table[] = {1, 1,
                         0, 0};
    TableDFA dfa(2, 2, trans_table);
    int exp_from[] = {0, 0, 1, 1};
    int exp_to[]   = {1, 1, 0, 0};
    ASSERT_EQ(ARRAYSIZE(exp_from), ARRAYSIZE(exp_to));
    test_valid_edges(dfa, exp_from, exp_to, ARRAYSIZE(exp_from));
  }
}

TEST(DFAInterfaceTest, LeaveSingleScc) {
  {
    int trans_table[] = {1, -1,
                         2, 3,
                         -1, -1,
                         -1, 4,
                         1, 5,
                         -1, -1};
    TableDFA dfa(6, 2, trans_table);
    int scc[] = {0, 1, 0, 1, 1, 0};
    SccPartition scc_partition(scc, 6);
    dfa.leave_single_scc(&scc_partition);
    // Node renumbering: 1->0, 3->1, 4->2.
    int exp_table[] = {-1, 1,
                       -1, 2,
                       0, -1};
    TableDFA exp_dfa(3, 2, exp_table);
    EXPECT_TRUE(exp_dfa.equals(dfa));
  }
}

}  // namespace
